/*
 * QSPI.c
 *
 *  Created on: 2022年1月12日
 *  Author: Laputa
 */

#include "QSPI.h"
#include "delay.h"
#include "data.h"

#define CS 1   //0 硬件片选，1 软件片选
#define QSPI_SS_LOW(a)   (*(volatile unsigned char *)(0x40010000+0x0021)) &= ~(1<<((((int)a-0x60000000)>>28)));
#define QSPI_SS_HIGH(a)  (*(volatile unsigned char *)(0x40010000+0x0021)) |= (1<<((((int)a-0x60000000)>>28)));

void QSPI_Standard_Init(qspi* t)  //标准单线模式
{
	t->U32_SSIENR.SSIC_EN = 0;  //失能QSPI0

	t->U32_CTRLR0.SPI_FRF = 0;  //标准SPI模式
	t->U32_CTRLR0.CFS = 0;		//
	t->U32_CTRLR0.SSTE = 0;		//
	t->U32_CTRLR0.SRL = 0;		//
	t->U32_CTRLR0.SLV_OE = 0;	//
	t->U32_CTRLR0.TMOD = 0;		//TX_AND_RX
	t->U32_CTRLR0.SCPOL = 0;	//闲置为高电平
	t->U32_CTRLR0.SCPH = 0;		//数据抓取从一个时钟周期的第二个边沿开始
	t->U32_CTRLR0.FRF = 0;		//摩托罗拉SPI模式
	t->U32_CTRLR0.DFS = 0x07;   //数据格式为8bit

//	LTPrintf("CTRLR0:%x \r\n",t->U32_CTRLR0);

	t->U32_CTRLR1.NDF = 0;		//传输数目
	t->U32_BAUDR.SCKDV = 4;  	//时钟频率
	t->U32_TXFTLR.TXFTHR = 0;   //转移开始FIFO等级
	t->U32_TXFTLR.TFT = 4;		//传输FIFO阈值
	t->U32_RXFTLR.RFT = 4;		//接受FIFO阈值

	t->U32_RXSDR.SE = 0;		//
	t->U32_RXSDR.RSD = 0;		//接收数据采样延迟

	t->U32_SPICTRLR0.CLK_STRETCH_EN = 0; //SPI时钟增强
	t->U32_SPICTRLR0.WAIT_CYCLES = 0;	 //等待周期
	t->U32_SPICTRLR0.INST_L = 0x02;		 //命令长度
	t->U32_SPICTRLR0.ADDR_L = 0x06;		 //地址长度
	t->U32_SPICTRLR0.TRANS_TYPE = 0;   //命令和地址的传输类型

	t->U32_SSIENR.SSIC_EN = 1;  //使能QSPI0
//	LTPrintf("SR:%x \r\n",t->U32_SR);

//------片选部分-------

	if(t == QSPI0)
	{
		CCM->U32_QSPIGPIOCR.QSPI0_SS_GPIOPEN = 1; //片选软件控制
		CCM->U32_QSPIGPIOCR.QSPI0_SS_PUE = 1;//片选上拉
		CCM->U32_QSPIGPIOCR.QSPI0_SS_OBE = 1;//输出模式
	}
	else if(t == QSPI1)
	{
		CCM->U32_QSPIGPIOCR.QSPI1_SS_GPIOPEN = 1; //片选软件控制
		CCM->U32_QSPIGPIOCR.QSPI1_SS_PUE = 1;//片选上拉
		CCM->U32_QSPIGPIOCR.QSPI1_SS_OBE = 1;//输出模式
	}
	else if(t == QSPI2)
	{
		CCM->U32_QSPIGPIOCR.QSPI2_SS_GPIOPEN = 1; //片选软件控制
		CCM->U32_QSPIGPIOCR.QSPI2_SS_PUE = 1;//片选上拉
		CCM->U32_QSPIGPIOCR.QSPI2_SS_OBE = 1;//输出模式
	}

	QSPI_SS_HIGH((int)t);
}

//void QSPI_STD_RX_DMA(unsigned char* p)
//{
//	DMA_CTL->U32_SERQR.SERQ |= 1<<1;        //开启QSPI0_RX_DMA_Channel 请求
//
//	DMA_TCD_01->saddr = (UINT32)(&QSPI0->DR);      //源地址
//	DMA_TCD_01->U32_Word1.ssize = 0;		 //源地址传输长度 8bit
//	DMA_TCD_01->U32_Word5.doff = 0;
//	DMA_TCD_01->U32_Word1.dsize = 0;		 //目的地址传输长度 8bit
//	DMA_TCD_01->U32_Word1.soff = 0;
//
//	DMA_TCD_01->nbytes = 256;			 //传输数目
//	DMA_TCD_01->slastr = 0;				 //
//	DMA_TCD_01->daddr = (UINT32)p;		 //目的地址
//
////	DMA_TCD_01->U32_Word7.biter = 1;
////	DMA_TCD_01->U32_Word5.citer = 1;
//	DMA_TCD_01->dlast_sgar = 0;
//
//	LTPrintf("Saddr:%x \r\n",DMA_TCD_01->saddr);
//	LTPrintf("Daddr:%x \r\n",DMA_TCD_01->daddr);
//}
//
//void QSPI_STD_TX_DMA(unsigned char* p)
//{
//	DMA_CTL->U32_SERQR.SERQ |= 1<<2;        //开启QSPI0_TX_DMA_Channel 请求
//
//	DMA_TCD_02->saddr = (UINT32)p;      //源地址
//	DMA_TCD_02->U32_Word1.ssize = 0;		 //源地址传输长度 8bit
//	DMA_TCD_02->U32_Word5.doff = 0;
//	DMA_TCD_02->U32_Word1.dsize = 0;		 //目的地址传输长度 8bit
//	DMA_TCD_02->U32_Word1.soff = 0;
//
//	DMA_TCD_02->nbytes = 256;			 //传输数目
//	DMA_TCD_02->slastr = 0;				 //
//	DMA_TCD_02->daddr = (UINT32)(&QSPI0->DR);		 //目的地址
//
////	DMA_TCD_02->U32_Word7.biter = 1;
////	DMA_TCD_02->U32_Word5.citer = 1;
//	DMA_TCD_02->dlast_sgar = 0;
//}

UINT16 QSPI_ReadWriteByte(qspi* t,UINT16 TxData)
{
//	LTPrintf("RWtest\r\n");
	while(t->U32_SR.TFE == 0)	//等待TX FIFO空
	{
		__asm("nop");
	}
	t->DR = TxData;	 	  		//发送一个byte
	while( t->U32_SR.RFNE == 0) 	//等RX FIFO非空，待接收完一个byte
	{
		__asm("nop");
	}
	return t->DR;          		//返回收到的数据
}

UINT16 W25Q_ReadID_STD(qspi* t)
{
	UINT16 temp;
	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x90);
	QSPI_ReadWriteByte(t,0x00);
	QSPI_ReadWriteByte(t,0x00);
	QSPI_ReadWriteByte(t,0x00);
	temp = QSPI_ReadWriteByte(t,0xFF);
	temp<<=8;
	temp |= QSPI_ReadWriteByte(t,0xFF)&0xFF;
	QSPI_SS_HIGH((int)t);
	return temp;
}

UINT8 W25Q_ReadSR_STD(qspi* t)   //读取W25QXX的状态寄存器
{
	UINT8 byte=0;
	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x05);
	byte=QSPI_ReadWriteByte(t,0Xff);
	QSPI_SS_HIGH((int)t);
	return byte;
}

void W25Q_Write_Enable_STD(qspi* t)
{
	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x06);
    QSPI_SS_HIGH((int)t);
}

void W25Q_Write_Disable_STD(qspi* t)
{
	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x04);
    QSPI_SS_HIGH((int)t);
}

void W25Q_Wait_Busy_STD(qspi* t)   		//等待空闲
{
	volatile signed int time;
	while((W25Q_ReadSR_STD(t)&0x01)==0x01) // 等待BUSY位清空
	{
		time = 5000;
		while(time)
		{
			__asm("nop");
			time--;
		};
	}
}

////读取SPI FLASH
////在指定地址开始读取指定长度的数据
////pBuffer:数据存储区
////ReadAddr:开始读取的地址(24bit)
////NumByteToRead:要读取的字节数(最大65535)
//void W25Q_Read_STD(qspi* t,u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
//{
// 	u16 i;
// 	QSPI_SS_LOW((int)t);                            		//使能器件
// 	QSPI_ReadWriteByte(t,0x03);         				//发送读取命令
//
//    QSPI_ReadWriteByte(t,(u8)((ReadAddr)>>16));  		//发送24bit地址
//    QSPI_ReadWriteByte(t,(u8)((ReadAddr)>>8));
//    QSPI_ReadWriteByte(t,(u8)ReadAddr);
//    for(i=0;i<NumByteToRead;i++)
//	{
//        pBuffer[i]=QSPI_ReadWriteByte(t,0XFF);   		//循环读数
//    }
//    QSPI_SS_HIGH((int)t);
//}

////SPI在一页(0~65535)内写入少于256个字节的数据
////在指定地址开始写入最大256字节的数据
////pBuffer:数据存储区
////WriteAddr:开始写入的地址(24bit)
////NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
//void W25Q_Write_Page_STD(qspi* t,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
//{
// 	u16 i;
//    W25Q_Write_Enable_STD(t);                  					//SET WEL
//    QSPI_SS_LOW((int)t);                            						//使能器件
//
//    QSPI_ReadWriteByte(t,0x02);      									//发送写页命令
//
//    QSPI_ReadWriteByte(t,(uint8_t)((WriteAddr)>>16)); 				//发送24bit地址
//    QSPI_ReadWriteByte(t,(uint8_t)((WriteAddr)>> 8));
//    QSPI_ReadWriteByte(t,(uint8_t)((WriteAddr)>> 0));
//    for(i=0;i<NumByteToWrite;i++)QSPI_ReadWriteByte(t,pBuffer[i]);	//循环写数
//
//    QSPI_SS_HIGH((int)t);  													//取消片选
//	W25Q_Wait_Busy_STD(t);					   						//等待写入结束
//}

//void W25Q_Write_Page_Quad(qspi* t,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)  //四线DMA写，自动片选和非自动片选都OK
//{
//	dma_tcd * d;
//	d =   (DMA_TCD_02) + (((int)t-0x60000000)>>28)*2;
//
// 	t->U32_SSIENR.SSIC_EN = 0;  //关闭
//
//	d->saddr = (UINT32)pBuffer;      //源地址
//	d->U32_Word1.smod = 0;
//	d->U32_Word1.ssize = 0;		 //源地址传输长度 8bit
//	d->U32_Word1.soff = 1;		 //源地址每次的偏移量
//	d->slastr = 0;
//
//	d->daddr = (UINT32)(&t->DR);		 //目的地址
//	d->U32_Word1.dmod = 0;
//	d->U32_Word1.dsize = 0;		 //目的地址传输长度 8bit
//	d->U32_Word5.doff = 0;		 //目的地址每次的偏移量
//	d->dlast_sgar = 0;
//
//	d->nbytes = 1;		 	 //小循环传输数目
//
//	d->U32_Word7.biter = NumByteToWrite;           //大循环次数
//	d->U32_Word5.citer = NumByteToWrite;		      //大循环次数
//
//	d->U32_Word5.citer_e_link = 0;
//	d->U32_Word7.biter_e_link = 0;
//
//	d->U32_Word7.d_req = 1;			  //硬件请求在结束时被禁用
//
//	d->U32_Word7.int_maj = 0;		 //大循环完成中断
//
//	DMA_CTL->U32_SERQR.SERQ = 2 + (((int)t-0x60000000)>>28)*2;        	 //开启QSPI0_TX_DMA_Channel 请求
//
//	QSPI_Standard_Init(t);  //切回单线
//	W25Q_Write_Enable_STD(t);                  					  //单线开启Flash写使能
//
//    QSPI_Quad_Init(t,CS);   //Quad Write Command 32H
//
// 	t->U32_SSIENR.SSIC_EN = 0;  //失能
//    t->U32_CTRLR1.NDF = NumByteToWrite-1;
// 	t->U32_CTRLR0.TMOD = 1;				//0：全双工，1：只发，2只读
//    t->U32_SPICTRLR0.WAIT_CYCLES = 0;   //等待周期数
//    t->U32_SPICTRLR0.TRANS_TYPE = 0;    //命令和地址的传输类型 0:都单线，  1:命令单线、地址按配置，2:命令和地址都按配置
//    t->U32_SPICTRLR0.ADDR_L = 6;		//地址长度0:No, 6:24bit, 8:32bit, 10:40bit
//
//    t->DMATDLR = 0;
//
//    t->U32_SSIENR.SSIC_EN = 1;  //使能
//
//#if CS
//    QSPI_SS_LOW((int)t);
//#endif
//    __asm("nop");__asm("nop");__asm("nop");
//    t->DR = 0x32;
//    t->DR = WriteAddr;
//
// 	t->U32_DMACR.TDMAE = 1;
//
// 	d->U32_Word7.done = 0;
//
// 	while(!d->U32_Word7.done)
// 	{
// 		__asm("nop");__asm("nop");__asm("nop");
// 	}
//
//#if CS
//    QSPI_SS_HIGH((int)t);
//#endif
//
//	QSPI_Standard_Init(t);  //切回单线
//	W25Q_Wait_Busy_STD(t);
//}
////无检验写SPI FLASH
////必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
////具有自动换页功能
////在指定地址开始写入指定长度的数据,但是要确保地址不越界!
////pBuffer:数据存储区
////WriteAddr:开始写入的地址(24bit)
////NumByteToWrite:要写入的字节数(最大65535)
////CHECK OK
//void W25QXX_Write_NoCheck(qspi* t,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite,unsigned char type)
//{
//	u16 pageremain;
//	pageremain=256-WriteAddr%256; //单页剩余的字节数
//	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
//	while(1)
//	{
//		if(type == 1)
//			W25Q_Write_Page_STD(t,pBuffer,WriteAddr,pageremain);
//		else if(type == 4)
//			W25Q_Write_Page_Quad(t,pBuffer,WriteAddr,pageremain);
//		if(NumByteToWrite==pageremain)break;//写入结束了
//	 	else //NumByteToWrite>pageremain
//		{
//			pBuffer+=pageremain;
//			WriteAddr+=pageremain;
//
//			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
//			if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
//			else pageremain=NumByteToWrite; 	  //不够256个字节了
//		}
//	}
//}
//
//void W25Q_BlockErase64KB_STD(qspi* t,u32 addr)
//{
//	addr*=(64*1024);
//	W25Q_Write_Enable_STD(t);                 	//SET WEL
//	W25Q_Wait_Busy_STD(t);
//	QSPI_SS_LOW((int)t);                           	  	//使能器件
//	QSPI_ReadWriteByte(t,0xD8);   			//发送片擦除命令
//
//	QSPI_ReadWriteByte(t,(uint8_t)((addr)>>16)); 			//发送24bit地址
//	QSPI_ReadWriteByte(t,(uint8_t)((addr)>>8));
//	QSPI_ReadWriteByte(t,(uint8_t)addr);
//	QSPI_SS_HIGH((int)t);                           	//取消片选
//	W25Q_Wait_Busy_STD(t);   				   	//等待芯片擦除结束
//}

void W25QXX_Open_QUAD(qspi* t)
{
	unsigned char temp1 = 0,temp2 = 0;

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x05);
	temp1 = QSPI_ReadWriteByte(t,0xFF);
	QSPI_SS_HIGH((int)t);

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x35);
	temp2 = QSPI_ReadWriteByte(t,0xFF);
	QSPI_SS_HIGH((int)t);
//LTPrintf("before %x\r\n",temp2);
	W25Q_Write_Enable_STD(t);

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x31);
	QSPI_ReadWriteByte(t,temp2|0x02);
	QSPI_SS_HIGH((int)t);

	W25Q_Wait_Busy_STD(t);

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x35);
	temp2 = QSPI_ReadWriteByte(t,0xFF);
	QSPI_SS_HIGH((int)t);

	if((temp2 & (1<<1)) != (1<<1))
	{
		QSPI_SS_LOW((int)t);
		QSPI_ReadWriteByte(t,0x01);
		QSPI_ReadWriteByte(t,temp1);
		QSPI_ReadWriteByte(t,temp2|(1<<1));
		QSPI_SS_HIGH((int)t);

		W25Q_Wait_Busy_STD(t);
	}
}

void W25QXX_Output_Driver_Strength(qspi* t)
{
	unsigned char temp = 0;

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x15);
	temp = QSPI_ReadWriteByte(t,0xFF);
	QSPI_SS_HIGH((int)t);

	W25Q_Write_Enable_STD(t);

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x11);
	temp = QSPI_ReadWriteByte(t,temp&0x9F);
	QSPI_SS_HIGH((int)t);

	W25Q_Wait_Busy_STD(t);

	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x15);
	temp = QSPI_ReadWriteByte(t,0xFF);
	QSPI_SS_HIGH((int)t);
}

char Test_QSPI_Port[6];
char QSPI_S[3][6]={"QSPI0","QSPI1","QSPI2"};

void QSPI_Port_Select(qspi* t)
{
	if(t == QSPI0)
	{
		memcpy(Test_QSPI_Port,QSPI_S[0],6);
	}
	else if(t == QSPI1)
	{
		memcpy(Test_QSPI_Port,QSPI_S[1],6);
	}
	else if(t == QSPI2)
	{
		memcpy(Test_QSPI_Port,QSPI_S[2],6);
	}
}

void QSPI_Quad_Init(qspi* t,unsigned char CS_type)
{
	t->U32_SSIENR.SSIC_EN = 0;  //失能QSPI0

	t->U32_CTRLR0.SPI_FRF = 2;  //双线模式  0:标准 ，1双线，2四线
	t->U32_CTRLR0.CFS = 0;		//
	t->U32_CTRLR0.SSTE = 0;		//
	t->U32_CTRLR0.SRL = 0;		//
	t->U32_CTRLR0.SLV_OE = 0;	//

	t->U32_CTRLR0.SCPOL = 0;	//闲置为高电平
	t->U32_CTRLR0.SCPH = 0;		//数据抓取从一个时钟周期的第二个边沿开始
	t->U32_CTRLR0.FRF = 0;		//摩托罗拉SPI模式
	t->U32_CTRLR0.DFS = 0x07;   //数据格式为8bit
	t->U32_CTRLR1.NDF = 0;		//传输数目
	t->U32_BAUDR.SCKDV = 2;  	//时钟频率

	t->U32_TXFTLR.TXFTHR = 0;   //转移开始FIFO等级
	t->U32_TXFTLR.TFT = 7;		//传输FIFO阈值
	t->U32_RXFTLR.RFT = 7;		//接受FIFO阈值
	t->U32_RXSDR.SE = 1;		//
	t->U32_RXSDR.RSD = 0;		//接收数据采样延迟  根据时钟频率调整，时钟越快延迟采样延迟越低
	t->U32_SPICTRLR0.CLK_STRETCH_EN = 1; //SPI时钟增强
	t->U32_SPICTRLR0.INST_L = 0x02;		 //命令长度 0:No,1:4bit,2:8bit,3:16bit
	t->U32_SSIENR.SSIC_EN = 1;  //使能QSPI0

//------片选部分-------
	if(CS_type == 1)
	{
		switch((UINT32)t)
		{
			case 0x60000000:
				CCM->U32_QSPIGPIOCR.QSPI0_SS_GPIOPEN = 1; //片选软件控制
				CCM->U32_QSPIGPIOCR.QSPI0_SS_PUE = 1;//片选上拉
				CCM->U32_QSPIGPIOCR.QSPI0_SS_OBE = 1;//输出模式
				break;

			case 0x70000000:
				CCM->U32_QSPIGPIOCR.QSPI1_SS_GPIOPEN = 1; //片选软件控制
				CCM->U32_QSPIGPIOCR.QSPI1_SS_PUE = 1;//片选上拉
				CCM->U32_QSPIGPIOCR.QSPI1_SS_OBE = 1;//输出模式

				break;

			case 0x80000000:
				CCM->U32_QSPIGPIOCR.QSPI2_SS_GPIOPEN = 1; //片选软件控制
				CCM->U32_QSPIGPIOCR.QSPI2_SS_PUE = 1;//片选上拉
				CCM->U32_QSPIGPIOCR.QSPI2_SS_OBE = 1;//输出模式
				break;

			default:break;
		}
	}
	else
	{
		switch((UINT32)t)
		{
			case 0x60000000:
				CCM->U32_QSPIGPIOCR.QSPI0_SS_GPIOPEN = 0; // 硬件控制
				break;
			case 0x70000000:
				CCM->U32_QSPIGPIOCR.QSPI1_SS_GPIOPEN = 0; // 硬件控制
				break;
			case 0x80000000:
				CCM->U32_QSPIGPIOCR.QSPI2_SS_GPIOPEN = 0; // 硬件控制
				break;
		}
	}
}

#include "lt168_dma.h"
//读取SPI FLASH
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25Q_Read_STD(qspi* t,u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
 	u16 i;
 	QSPI_SS_LOW((int)t);                            		//使能器件
 	QSPI_ReadWriteByte(t,0x03);         				//发送读取命令

    QSPI_ReadWriteByte(t,(u8)((ReadAddr)>>16));  		//发送24bit地址
    QSPI_ReadWriteByte(t,(u8)((ReadAddr)>>8));
    QSPI_ReadWriteByte(t,(u8)ReadAddr);
    for(i=0;i<NumByteToRead;i++)
	{
        pBuffer[i]=QSPI_ReadWriteByte(t,0XFF);   		//循环读数
    }
    QSPI_SS_HIGH((int)t);
}

u8 rx_test_buf[256]={0};

void QSPI_Quad_DMA2RGB(qspi* t,u32 flash_addr,u32 data_sum)     //片选和非片选都OK
{
	u32 i = 0;
	u32 len = 65280,cnt = 4;
//	int num = 256;

//	dma_tcd * d;
//	d =   (DMA_TCD_01) + (((int)t-0x60000000)>>28)*2;
//	CCM->U32_QSPIGPIOCR.QSPI1_SS_GPIOPEN = 1; //片选软件控制
//	CCM->U32_QSPIGPIOCR.QSPI1_SS_PUE = 1;//片选上拉
//	CCM->U32_QSPIGPIOCR.QSPI1_SS_OBE = 1;//输出模式
//	QSPI_Port_Select(t);

//	CCM->U32_QSPIXIPMCFR.QSPI1_XIPEN = 0;
//	CCM->U32_QSPIXIPMCFR.QSPI1_DATA_ENCR_EN = 0;
//	W25QXX_Exit_QPI(t);

	QSPI_Standard_Init(t);  //QSPI0 单线初始化
//	LTPrintf("%s_Quad_DMA_Test \r\n",Test_QSPI_Port);
//	LTPrintf("%x \r\n",W25Q_ReadID_STD(t)); //输出外挂Flash ID号 确认是否正确连接外挂Flash

//	W25Q_Read_STD(t,rx_test_buf,flash_addr,256);
//	for(i=0;i<256;i++)
//	{
//		if(i%16==0)	LTPrintf("\r\n");
//		LTPrintf("%x ",rx_test_buf[i]);
//	}

	W25QXX_Open_QUAD(t);
//	W25QXX_Output_Driver_Strength(t);    //Flash 输出能力

//====================================== 6BH ======================================

//======================================= DMA ======================================

	dma_tcd *test_ch;
	dma_control_config_ts dma_control_config;
	dma_tcd_config_ts dma_tcd_config;

	/* DMA 控制部分，使用默认配置 */
	DMA_Control_Reset(&dma_control_config);
	DMA_Control_Init(&dma_control_config);

	/* TCD 部分 */
	DMA_TCD_Reset(&dma_tcd_config);  //更改新配置之前必须清空该结构体

	/* DMA Channel */
	test_ch = DMA_TCD_03;

//	/* Interrupt  */
//	NULL;
//	dma_tcd_config.minor_link = Enable;
//	dma_tcd_config.minor_link_channel = test_ch - DMA_TCD_00;  //Channel num (0-15)

//	dma_tcd_config.bwc = DMA_EngineStalls_4cycles;

	for(i=0;i<cnt;i++)
	{
		//Minor Loop---------------------------------------------------------------
	//	d->saddr = (UINT32)(&t->DR);      //源地址
	//	d->U32_Word1.smod = 0;
	//	d->U32_Word1.ssize = 0;		 //源地址传输长度 8bit
	//	d->U32_Word1.soff = 0;
	//	d->slastr = 0;

		/* Source part---Start */
		dma_tcd_config.source = (UINT32)(&t->DR);		     // 源地址
		dma_tcd_config.source_modulo = DMA_MOD_Disable;		 // 设0则禁用，设 0<n<=31,则源地址低N位可以变，一般禁用比较鸡肋，无实际应用场合
		dma_tcd_config.source_datasize = DMA_DataSize_8bit;  // 源地址传输长度  0:8bit, 1:16bit, 2:32bit
		dma_tcd_config.source_offset = 0;					 // 每次向总线读取数据后源地址的偏移量 (带符号能向上、向下、不变)
		dma_tcd_config.source_last_address_adjustment = 0;	 // 大循环计数结束后，源地址写回到TCD的偏移量 (带符号能向上、向下、不变)
		/* Source part---End */

	//	d->daddr = (UINT32)Flash_buff_RX;		 //目的地址
	//	d->U32_Word1.dmod = 0;
	//	d->U32_Word1.dsize = 0;		 //目的地址传输长度 8bit
	//	d->U32_Word5.doff = 1;       //目的地址每次的偏移量
	//	d->dlast_sgar = 0;

		/* Destination part---Start */
		dma_tcd_config.destin = 0x840000+(len*i);		     // 目的地址
		dma_tcd_config.destin_modulo = DMA_MOD_Disable;		 // 设0则禁用，设 0<n<=31,则目的地址低N位可以变，一般禁用比较鸡肋，无实际应用场合
		dma_tcd_config.destin_datasize = DMA_DataSize_8bit; // 目的地址传输长度 0:8bit, 1:16bit, 2:32bit
		dma_tcd_config.destin_offset = 1;					 // 每次向总线写入数据后目的地址的偏移量 (带符号能向上、向下、不变)
		dma_tcd_config.destin_last_address_adjustment = 0;	 // 大循环计数结束后，目的地址写回到TCD的偏移量 (带符号能向上、向下、不变)
		/* Destination part---End */

	//	d->nbytes = 1; 			 //传输数目
	//	//Major Loop---------------------------------------------------------------
	//	d->U32_Word7.biter = num;           //大循环次数
	//	d->U32_Word5.citer = num;		    //小循环次数
	//
	//	d->U32_Word5.citer_e_link = 0;
	//	d->U32_Word7.biter_e_link = 0;
	//
	//	d->U32_Word7.d_req = 1;
	//	d->U32_Word7.int_maj = 0;
	// 	d->U32_Word7.start = 0;
	// 	d->U32_Word7.bwc = 2;

		dma_tcd_config.minor_transfer_num = len; /* 小循环传输数目 */

		/* Major Loop--- */
		dma_tcd_config.major_loop_num = 1;  /* 小循环次数 */

	// 	DMA_CTL->U32_SERQR.SERQ = 1 + (((int)t-0x60000000)>>28)*2;        	 //开启QSPI_RX_DMA_Channel 请求
	//======================================= DMA ======================================
	 	DMA_Channel_Hardware_Request_Enable(test_ch);
		DMA_TCD_Init(test_ch,&dma_tcd_config);

		/* 开启通道的错误中断，判断配置是否出错 */
		EIC->IER |= 1<<5;
		DMA_Channel_Error_Interrupt_Enable(test_ch);

	 	QSPI_Quad_Init(t,CS);   //Quad Read Command 6BH

	 	t->U32_SSIENR.SSIC_EN = 0;  //失能QSPI
		t->U32_CTRLR0.TMOD = 2;		//0：全双工，1：只发，2只读
		t->U32_CTRLR1.NDF = len-1;
		t->U32_SPICTRLR0.WAIT_CYCLES = 8;	 //等待周期
		t->U32_SPICTRLR0.ADDR_L = 6;	   //地址长度0:No, 6:24bit, 8:32bit
		t->U32_SPICTRLR0.TRANS_TYPE = 0;    //命令和地址的传输类型 0:都单线，  1:命令单线、地址按配置，2:命令和地址都按配置
		t->DMARDLR = 0;
	    t->U32_SSIENR.SSIC_EN = 1;  //使能QSPI

		__asm("nop");__asm("nop");__asm("nop");
		t->U32_DMACR.RDMAE = 1;

	#if CS
	 	QSPI_SS_LOW((int)t);             //使能器件               		//使能器件
	#endif

		t->DR = 0x6B;
		t->DR = flash_addr+(len*i);

	// 	d->U32_Word7.done = 0;
	//
	// 	while(!d->U32_Word7.done)
	// 	{
	// 		__asm("nop");__asm("nop");__asm("nop");
	// 	}

		/* 手动清除通道的done位 */
		DMA_Channel_Clear_Done(test_ch);

		/* 软件启动 software start */
	//	DMA_Channel_Start(test_ch);

		while (DMA_Channel_Check_Donebit(test_ch) == 0) /* 直接等待大循环完成 */
		{
			asm("nop");
		}
		t->U32_DMACR.RDMAE = 0;

	#if CS
	 	QSPI_SS_HIGH((int)t);
	#endif
	}
//	LTPrintf("\r\nRGB");
//	for(i=0;i<256;i++)
//	{
//		if(i%16==0)	LTPrintf("\r\n");
//		LTPrintf("%x ",IO_READ8(0x840000+i));
//	}
}

void LT168_Display_Picture(u16 x,u16 y,u16 w,u16 h,u32 flash_addr)     //片选和非片选都OK
{
	u32 i = 0;
	u32 len = w*2,cnt = h;

	qspi* t = QSPI1;
	dma_tcd *test_ch = DMA_QSPI1_RX_Channel;

	dma_control_config_ts dma_control_config;
	dma_tcd_config_ts dma_tcd_config;

	/* DMA 控制部分，使用默认配置 */
	DMA_Control_Reset(&dma_control_config);
	DMA_Control_Init(&dma_control_config);

	/* TCD 部分 */
	DMA_TCD_Reset(&dma_tcd_config);  //更改新配置之前必须清空该结构体

	/* DMA Channel */

	/* Source part---Start */
	dma_tcd_config.source = (UINT32)(&t->DR);		     // 源地址
	dma_tcd_config.source_modulo = DMA_MOD_Disable;		 // 设0则禁用，设 0<n<=31,则源地址低N位可以变，一般禁用比较鸡肋，无实际应用场合
	dma_tcd_config.source_datasize = DMA_DataSize_8bit;  // 源地址传输长度  0:8bit, 1:16bit, 2:32bit
	dma_tcd_config.source_offset = 0;					 // 每次向总线读取数据后源地址的偏移量 (带符号能向上、向下、不变)
	dma_tcd_config.source_last_address_adjustment = 0;	 // 大循环计数结束后，源地址写回到TCD的偏移量 (带符号能向上、向下、不变)
	/* Source part---End */

	/* Destination part---Start */
	dma_tcd_config.destin = 0x840000 + 2*LCD_XSIZE_TFT*y + 2*x;		     // 目的地址
	dma_tcd_config.destin_modulo = DMA_MOD_Disable;		 // 设0则禁用，设 0<n<=31,则目的地址低N位可以变，一般禁用比较鸡肋，无实际应用场合
	dma_tcd_config.destin_datasize = DMA_DataSize_8bit; // 目的地址传输长度 0:8bit, 1:16bit, 2:32bit
	dma_tcd_config.destin_offset = 1;					 // 每次向总线写入数据后目的地址的偏移量 (带符号能向上、向下、不变)
	dma_tcd_config.destin_last_address_adjustment = (LCD_XSIZE_TFT-w)*2;	 // 大循环计数结束后，目的地址写回到TCD的偏移量 (带符号能向上、向下、不变)
	/* Destination part---End */

	dma_tcd_config.minor_transfer_num = len; /* 小循环传输数目 */
	/* Major Loop--- */
	dma_tcd_config.major_loop_num = 1;  /* 小循环次数 */
	dma_tcd_config.d_req = 1;
//======================================= DMA ======================================
	DMA_TCD_Init(test_ch,&dma_tcd_config);

	/* 开启通道的错误中断，判断配置是否出错 */
	EIC->IER |= 1<<5;
	DMA_Channel_Error_Interrupt_Enable(test_ch);

	t->U32_SSIENR.SSIC_EN = 0;  //失能QSPI
	t->U32_CTRLR1.NDF = len-1;
	t->U32_SSIENR.SSIC_EN = 1;  //使能QSPI

//	__asm("nop");__asm("nop");__asm("nop");

	for(i=0;i<cnt;i++)
	{
		DMA_Channel_Hardware_Request_Enable(test_ch);
		DMA_Channel_Clear_Done(test_ch);
		t->U32_DMACR.RDMAE = 1;

	#if CS
	 	QSPI_SS_LOW((int)t);             //使能器件               		//使能器件
	#endif

		t->DR = 0x6B;
		t->DR = flash_addr+(len*i);

//		/* 手动清除通道的done位 */

		/* 软件启动 software start */
	//	DMA_Channel_Start(test_ch);

		while (DMA_Channel_Check_Donebit(test_ch) == 0) /* 直接等待大循环完成 */
		{
			asm("nop");
		}
		t->U32_DMACR.RDMAE = 0;

	#if CS
	 	QSPI_SS_HIGH((int)t);
	#endif
	}
}

//---------------------------------------------------------- XIP ----------------------

void W25QXX_Enter_QPI_STD(qspi* t)
{
	QSPI_SS_LOW((int)t);
	QSPI_ReadWriteByte(t,0x38);
	QSPI_SS_HIGH((int)t);
}

void QSPI0_Handler(void)
{
	LTPrintf("QSPI0_Handler\r\n");
}

void QSPI1_Handler(void)
{
	LTPrintf("QSPI1_Handler\r\n");
}

void QSPI2_Handler(void)
{
	unsigned char temp;
	LTPrintf("QSPI2_Handler\r\n");
	temp = QSPI2->ISR;

	LTPrintf("SR:%x\r\n",QSPI2->SR);
	LTPrintf("ISR:%x\r\n",temp);
	LTPrintf("R:%d\r\n",QSPI2->U32_RXFLR.RXTFL);
	LTPrintf("T:%d\r\n",QSPI2->U32_TXFLR.TXTFL);

	if((temp&0x10) == 0x10)  //发送FIFO满
	{
		for(;(temp&0x10) == 0x10;)
			QSPI2->DR;
	}
	if((temp&0x02) == 0x02)  //TX FIFO Overflow
	{
		QSPI2->U32_TXOICR.TXOICR;
	}
	if((temp&0x04) == 0x04)  //RX FIFO Underflow
	{
		QSPI2->U32_RXUICR.RXUICR;
	}
}

void QSPI_INT_Test(qspi *t)
{
	unsigned short i = 0;

	EIC->U32_IER.IE_QSPI0 = 1;
	EIC->U32_IER.IE_QSPI1 = 1;
	EIC->U32_IER.IE_QSPI2 = 1;

	t->U32_SSIENR.SSIC_EN = 0;  //失能QSPI0

	t->U32_CTRLR0.SPI_FRF = 0;  //标准SPI模式
	t->U32_CTRLR0.CFS = 0;		//
	t->U32_CTRLR0.SSTE = 0;		//
	t->U32_CTRLR0.SRL = 0;		//
	t->U32_CTRLR0.SLV_OE = 0;	//
	t->U32_CTRLR0.TMOD = 2;		//TX_AND_RX
	t->U32_CTRLR0.SCPOL = 0;	//闲置为高电平
	t->U32_CTRLR0.SCPH = 0;		//数据抓取从一个时钟周期的第二个边沿开始
	t->U32_CTRLR0.FRF = 0;		//摩托罗拉SPI模式
	t->U32_CTRLR0.DFS = 0x07;   //数据格式为8bit

//	LTPrintf("CTRLR0:%x \r\n",t->U32_CTRLR0);

	t->U32_CTRLR1.NDF = 0;		//传输数目
	t->U32_BAUDR.SCKDV = 8;  	//时钟频率
	t->U32_TXFTLR.TXFTHR = 0;   //转移开始FIFO等级
	t->U32_TXFTLR.TFT = 9;		//传输FIFO阈值
	t->U32_RXFTLR.RFT = 8;		//接受FIFO阈值

	t->U32_RXSDR.SE = 0;		//
	t->U32_RXSDR.RSD = 0;		//接收数据采样延迟

	t->U32_SPICTRLR0.CLK_STRETCH_EN = 0; //SPI时钟增强
	t->U32_SPICTRLR0.WAIT_CYCLES = 0;	 //等待周期
	t->U32_SPICTRLR0.INST_L = 0x02;		 //命令长度
	t->U32_SPICTRLR0.ADDR_L = 0x06;		 //地址长度
	t->U32_SPICTRLR0.TRANS_TYPE = 0;   //命令和地址的传输类型

	t->U32_SSIENR.SSIC_EN = 1;  //使能QSPI0

//------片选部分-------

	if(t == QSPI0)
	{
		CCM->U32_QSPIGPIOCR.QSPI0_SS_GPIOPEN = 1; //片选软件控制
		CCM->U32_QSPIGPIOCR.QSPI0_SS_PUE = 1;//片选上拉
		CCM->U32_QSPIGPIOCR.QSPI0_SS_OBE = 1;//输出模式
	}
	else if(t == QSPI1)
	{
		CCM->U32_QSPIGPIOCR.QSPI1_SS_GPIOPEN = 1; //片选软件控制
		CCM->U32_QSPIGPIOCR.QSPI1_SS_PUE = 1;//片选上拉
		CCM->U32_QSPIGPIOCR.QSPI1_SS_OBE = 1;//输出模式
	}
	else if(t == QSPI2)
	{
		CCM->U32_QSPIGPIOCR.QSPI2_SS_GPIOPEN = 1; //片选软件控制
		CCM->U32_QSPIGPIOCR.QSPI2_SS_PUE = 1;//片选上拉
		CCM->U32_QSPIGPIOCR.QSPI2_SS_OBE = 1;//输出模式
	}

	QSPI_SS_HIGH((int)t);

	QSPI_SS_LOW((int)t);

//	for(i = 0;i<10;i++)
//	{
		t->DR;
//	}

    QSPI_SS_HIGH((int)t);

    while(1);
}

void QSPI_Demo(void)
{
//	RGB_Init();
//	LCD_BL_Init();
	QSPI_Standard_Init(QSPI1);  //QSPI0 单线初始化
	W25QXX_Open_QUAD(QSPI1);
	QSPI_Quad_Init(QSPI1,CS);   //Quad Read Command 6BH
	//	W25QXX_Output_Driver_Strength(t);    //Flash 输出能力
	while(1)
	{
//		LTPrintf("Picture1\r\n");
		EPORT0->EPDR |= 0x10;
		LT168_Display_Picture(0,0,480,272,0);
		DelayMS(1000);
//		LTPrintf("Picture2\r\n");
		EPORT0->EPDR &=~0x10;
		LT168_Display_Picture(0,0,480,270,0x0003fc00);
		DelayMS(1000);
		LT168_Display_Picture(50,1,270,270,0x0007f080);
		DelayMS(1000);
		LT168_Display_Picture(200,70,205,146,0x000a2a08);
		DelayMS(1000);
	}
}

//------------------------------------ QPI drive ------------------------------------
